package com.xxl.sso.server.service.impl;

import com.xxl.sso.core.entity.vo.req.SysCacheAddUpdateReqVO;
import com.xxl.sso.core.entity.vo.res.SysCacheResVO;
import com.xxl.sso.server.core.result.ReturnT;
import com.xxl.sso.server.domain.cache.SysCacheDomain;

import com.xxl.sso.server.entity.cache.SysCache;
import com.xxl.sso.server.service.SysCacheService;
import com.xxl.sso.server.util.JedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Base64;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 类SysCacheImpl.java的实现描述：系统缓存表
 *
 */
@Slf4j
@Service("sysCacheService")
public class SysCacheServiceImpl implements SysCacheService {

    @Autowired
    private SysCacheDomain sysCacheDomain;

    @Autowired
    private ThreadPoolExecutor executor;

    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    @Override
    public ReturnT<SysCacheResVO> findByCacheKey(String cacheKey) {
        SysCacheResVO sysCacheResVO = new SysCacheResVO();
        CompletableFuture<SysCache> selectCompletableFuture = CompletableFuture.supplyAsync(() -> sysCacheDomain.getOneByCacheKey(cacheKey), executor).thenApply((sysCache) -> {
            //根据查询结果判断是否删除
            if(!ObjectUtils.isEmpty(sysCache)){
                LocalDateTime expiration = sysCache.getGmtExpiration();
                if(null != expiration){
                    //-1:小于
                    int compareResult = expiration.compareTo(LocalDateTime.now());
                    //过期删除数据库对象，并返回null
                    if(compareResult <= 0 && !ObjectUtils.isEmpty(sysCache.getId())){//过期
                        int deleteResult = sysCacheDomain.deleteById(sysCache.getId());
                        if(deleteResult > 0){
                            sysCache = null;
                        }
                    }
                }
            }
            return sysCache;
        });
        try {
            CompletableFuture.allOf(selectCompletableFuture).get();
            SysCache sysCache = selectCompletableFuture.get();
            if(!ObjectUtils.isEmpty(sysCache) && !ObjectUtils.isEmpty(sysCache.getCacheValue())){
                sysCacheResVO.setCacheKey(cacheKey);
                sysCacheResVO.setCacheValueObj(JedisUtil.unserialize(Base64.getDecoder().decode(sysCache.getCacheValue())));
            }
        } catch (Exception e) {
            log.error("SysCacheService findByCacheKey() 异步线程异常：", e);
            return new ReturnT(ReturnT.FAIL_CODE, "findByCacheKey异步执行异常");
        }
        return new ReturnT(sysCacheResVO);
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    @Override
    public ReturnT<Boolean> deleteByCacheKey(String cacheKey) {
        Boolean result = false;
        CompletableFuture<Integer> deleteCompletableFuture = CompletableFuture.supplyAsync(() -> {
            int deleteResult = sysCacheDomain.deleteByCacheKey(cacheKey);
            return deleteResult;
        }, executor);
        try {
            CompletableFuture.allOf(deleteCompletableFuture).get();
            Integer deleteResult = deleteCompletableFuture.get();
            if(null != deleteResult && deleteResult >= 0){
                result = true;
            }
        } catch (Exception e) {
            log.error("SysCacheService deleteByCacheKey() 异步线程异常：", e);
            return new ReturnT(ReturnT.FAIL_CODE, "deleteByCacheKey异步执行异常");
        }
        return new ReturnT(result);
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    @Override
    public ReturnT<Boolean> addOrUpdateSysCache(SysCacheAddUpdateReqVO vo) {
        synchronized (this) {
            Boolean result;
            CompletableFuture<Boolean> addOrUpdateCompletableFuture = CompletableFuture.supplyAsync(() -> {
                Integer updateResult = 0;
                Integer insertResult = 0;
                if (!ObjectUtils.isEmpty(vo) && !ObjectUtils.isEmpty(vo.getCacheKey())) {
                    SysCache sysCache = new SysCache();
                    constructSysCache(vo, sysCache);
                    //List<SysCache> cacheList = sysCacheDomain.getValidListByCondition(vo.getCacheKey());
                    List<SysCache> cacheList = sysCacheDomain.getListByCondition(vo.getCacheKey());
                    if (null != cacheList && !cacheList.isEmpty()) {//更新
                        updateResult = sysCacheDomain.updateByCacheKey(sysCache);
                    } else {//新增
                        insertResult = sysCacheDomain.insert(sysCache);
                    }
                }
                if ((null != updateResult && updateResult >= 0) || (null != insertResult && insertResult >= 0)) {
                    return true;
                } else {
                    return false;
                }
            }, executor);
            try {
                CompletableFuture.allOf(addOrUpdateCompletableFuture).get();
                boolean futureResult = addOrUpdateCompletableFuture.get();
                result = futureResult;
            } catch (Exception e) {
                log.error("SysCacheService addOrUpdateSysCache() 异步线程异常：", e);
                return new ReturnT(ReturnT.FAIL_CODE, "addOrUpdateSysCache异步执行异常");
            }
            return new ReturnT(result);
        }
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    @Override
    public ReturnT<Boolean> deleteExpiredSysCache() {
        Boolean returnResult = false;
        CompletableFuture<Integer> deleteCompletableFuture = CompletableFuture.supplyAsync(() -> {
            Integer result = sysCacheDomain.deleteExpiredSysCache();
            return result;
        }, executor);
        try {
            CompletableFuture.allOf(deleteCompletableFuture).get();
            Integer result = deleteCompletableFuture.get();
            if(null != result && result >= 0){
                returnResult = true;
            }
        } catch (Exception e) {
            log.error("SysCacheService deleteExpiredSysCache() 异步线程异常：", e);
            return new ReturnT(ReturnT.FAIL_CODE, "deleteExpiredSysCache");
        }
        return new ReturnT(returnResult);
    }

    private void constructSysCache(SysCacheAddUpdateReqVO vo,SysCache sysCache){
        sysCache.setCacheKey(vo.getCacheKey());
        if(!ObjectUtils.isEmpty(vo.getXxlSsoUser())){
            sysCache.setCacheValue(Base64.getEncoder().encodeToString(JedisUtil.serialize(vo.getXxlSsoUser())));
        }
        if(!ObjectUtils.isEmpty(vo.getExpireSecond())){
            LocalDateTime expirationTime = LocalDateTime.now();
            expirationTime = expirationTime.plus(vo.getExpireSecond(), ChronoUnit.SECONDS);
            sysCache.setGmtExpiration(expirationTime);
        }
    }
}
